/*********************************************************************
* FileName    : hmc830lp6ge.c
* Dependencies: hmc830 API
* Processor   : PIC24F
* Complier    : Microchip C30 ,MPLAB IDE v8.90 or higher
* Company     : .
*
* Software License Agreement
*
*
*
* Author : Lau
* Date   : 7/14/2014
********************************************************************/

#include "mtype.h"
#include "hmc830lp6ge_type.h"
#include "hmc830lp6ge.h"
#include "channel_01.h"
#include "bsp.h"

/*
*********************************************************************************************************
*                                                CONSTANTS
*********************************************************************************************************
*/
#define PDF			50000.0				// ***KHz
#define RF_MAX		3000000.0			// ***KHz
#define RF_MIN		25000.0				// ***KHz
#define _2_24		(1LL << 24)			// 2^24

/*********************************************************************
 * Name        : void init_channal(USR_INT08U lchannal)
 * Function    : initial channal @lchannal registers(memory)
 * PreCondition: None
 * Input       : @lchannal hmc830 channel number
 * Output      : NULL
 * Side Effects: None
 * Author      : Lau
 * Time/Creat  : 15:50 7/8/2014
 * Time/Modify : 10:50 7/15/2014
 * Note        : None
 ********************************************************************/
void init_channal(USR_INT08U lchannal)
{
	switch(lchannal){
	case 1:
		init_ch1();
		break;
	case 2:
	
		break;
	}
	write_pll(lchannal, REG01H, 0x02);
	write_pll(lchannal, REG02H, 0x01);
	write_pll(lchannal, REG03H, 0x20);
	write_vco(lchannal, VCO_REG02H, 0b111000001);
	write_vco(lchannal, VCO_REG03H, 0b1010000);
	write_vco(lchannal, VCO_REG00H, 0x0);
	write_pll(lchannal, REG06H, 0x200B4A);
	write_pll(lchannal, REG07H, 0xCCD);
	write_pll(lchannal, REG09H, 0x5C3FFF);
	write_pll(lchannal, REG0AH, 0x2046);
	write_pll(lchannal, REG0FH, 0x81);
	write_pll(lchannal, REG04H, 0x00);

}
/*********************************************************************
 * Name        : USR_INT32U print_pll(USR_INT08U lchannal, USR_INT08U reg_addr)
 * Function    : print vco register of hmc830 at channel lchannal, 
 *					return to console or other user task
 * PreCondition: None
 * Input       : @lchannal hmc830 channel number, @reg_addr pll register(memory) address
 * Output      : NULL
 * Side Effects: None
 * Author      : Lau
 * Time/Creat  : 15:50 7/8/2014
 * Time/Modify : 09:53 7/15/2014
 * Note        : None
 ********************************************************************/
USR_INT32U print_pll(USR_INT08U lchannal, USR_INT08U reg_addr)
{
	OM_CMD_STRUCT tmp;
//	USR_INT32U reg_valu;
	
	tmp.zero = 0;
	tmp.dat_b.regibits = reg_addr;
	switch(lchannal){
	case 1:
		return get_reg_ch1(&tmp);
		break;
	case 2:
//		return get_reg_ch2(&tmp);
		break;
	default :
		break;
	}
	
	return -1;
}
/*********************************************************************
 * Name        : USR_INT32U print_vco(USR_INT08U lchannal, USR_INT08U vco_addr)
 * Function    : print vco register of hmc830 at channel lchannal, 
 *					return to console or other user task
 * PreCondition: None
 * Input       : @lchannal hmc830 channel number, @vco_addr vco register(memory) address
 * Output      : NULL
 * Side Effects: None
 * Author      : Lau
 * Time/Creat  : 15:50 7/8/2014
 * Time/Modify : 09:50 7/15/2014
 * Note        : None
 ********************************************************************/
USR_INT32U print_vco(USR_INT08U lchannal, USR_INT08U vco_addr)
{
	OM_CMD_STRUCT tmp;
//	USR_INT32U reg_valu;
	
	tmp.zero = 0;
	tmp.dat_b.regibits = REG05H;
	tmp.dat_v.regi_vco = vco_addr;
	switch(lchannal){
	case 1:
		return get_reg_ch1(&tmp);
		break;
	case 2:
//		return get_reg_ch2(&tmp);
		break;
	default :
		break;
	}
	
	return -1;
}
/*********************************************************************
 * Name        : void write_pll(USR_INT08U lchannal, USR_INT08U reg_addr, USR_INT32U reg_valu)
 * Function    : write pll register of hmc830 at channel lchannal, at the same
 *					time save the value to memory
 * PreCondition: None
 * Input       : @lchannal hmc830 channel number, @reg_addr pll register(writable) address
 * 					@reg_valu the value to write
 * Output      : NULL
 * Side Effects: None
 * Author      : Lau
 * Time/Creat  : 15:50 7/8/2014
 * Time/Modify : 09:17 7/15/2014
 * Note        : None
 ********************************************************************/
void write_pll(USR_INT08U lchannal, USR_INT08U reg_addr, USR_INT32U reg_valu)
{
	OM_CMD_STRUCT tmp;
	
	tmp.zero = 0;
	tmp.dat_b.regibits = reg_addr;
	tmp.dat_b.databits = reg_valu;
	if(reg_addr == REG00H || reg_addr == REG05H || reg_addr == REG0DH || reg_addr == REG0EH || reg_addr > REG0FH){
		return;									// cannot be written
	}
	switch(lchannal){
	case 1:
		set_reg_ch1(&tmp);
		break;
	case 2:
//		set_reg_ch2(&tmp);
		break;
	default :
		break;
	}
	SPI_Send(lchannal, (USR_INT08U *)&tmp, 4);
	
}
/*********************************************************************
 * Name        : void write_vco(USR_INT08U lchannal, USR_INT08U vco_addr, USR_INT32U vco_valu)
 * Function    : write vco register of hmc830 at channel lchannal, at the same
 *					time save the value to memory
 * PreCondition: None
 * Input       : @lchannal hmc830 channel number, @vco_addr vco register(writable) address, 
 * 					@vco_valu the value to write
 * Output      : NULL
 * Side Effects: None
 * Author      : Lau
 * Time/Creat  : 15:50 7/8/2014
 * Time/Modify : 09:11 7/15/2014
 * Note        : None
 ********************************************************************/
void write_vco(USR_INT08U lchannal, USR_INT08U vco_addr, USR_INT32U vco_valu)
{
	OM_CMD_STRUCT tmp;
	
	tmp.zero = 0;
	tmp.dat_b.regibits = REG05H;
	tmp.dat_v.regi_vco = vco_addr;
	tmp.dat_v.data_vco = vco_valu;
	if(vco_addr > VCO_REG03H){						// cannot be written
		return;
	}
	switch(lchannal){
	case 1:
		set_reg_ch1(&tmp);
		break;
	case 2:
//		set_reg_ch2(&tmp);
		break;
	default :
		break;
	}
	SPI_Send(lchannal, (USR_INT08U *)&tmp, 4);

}
/*********************************************************************
 * Name        : USR_INT08U read_pll(USR_INT08U lchannal, USR_INT08U reg_addr)
 * Function    : read pll register of hmc830 at channel lchannal, at the same
 *					time save the value to memory
 * PreCondition: None
 * Input       : @lchannal hmc830 channel number, @reg_addr pll register(readable) address
 * Output      : -1 error, 0 success
 * Side Effects: None
 * Author      : Lau
 * Time/Creat  : 15:50 7/8/2014
 * Time/Modify : 08:35 7/15/2014
 * Note        : None
 ********************************************************************/
USR_INT08U read_pll(USR_INT08U lchannal, USR_INT08U reg_addr)
{
	USR_INT32U trd_reg;
	OM_CMD_STRUCT tmp;
	
	if(reg_addr == REG05H || reg_addr == REG0DH || reg_addr == REG0EH || reg_addr > REG13H){
		return -1;
	}
	tmp.zero = 0;
	tmp.dat_b.databits = reg_addr;									// Read reg reg_addr,other must be zero
	SPI_Send(lchannal, (USR_INT08U *)&tmp, 4);								// Write cycle
	trd_reg = *(USR_INT32U *)SPI_Send(lchannal, (USR_INT08U *)&tmp, 4) >> 2;	// Read cycle, right shift 2bits to abandon chip addr
	
	tmp.dat_b.regibits = trd_reg & 0x1F;
	tmp.dat_b.databits = trd_reg >> 5;
	switch(lchannal){
	case 1:
		set_reg_ch1(&tmp);
		break;
	case 2:
//		set_reg_ch2(&tmp);
		break;
	default :
		break;
	}
	return 0;
}

/*********************************************************************
 * Name        : void out_freq(USR_INT08U lchannal, USR_FP64 rf_freq)
 * Function    : read pll register of hmc830 at channel lchannal, at the same
 *					time save the value to memory
 * PreCondition: None
 * Input       : @lchannal hmc830 channel number, @rf_freq rf output frequence
 * Output      : NULL
 * Side Effects: None
 * Author      : Lau
 * Time/Creat  : 15:50 7/8/2014
 * Time/Modify : 08:35 7/15/2014
 * Note        : None
 ********************************************************************/
 static USR_INT32U rf_div_radio(USR_FP64 rf_freq);
void out_freq(USR_INT08U lchannal, USR_FP64 rf_freq)
{
	USR_INT32U	tfrq_intg;
	USR_INT32U	tfrq_frac;
	USR_INT32U	tdiv_radio;
	static USR_FP64	tfreq;				// static for test
	
	if(rf_freq > RF_MAX){
		rf_freq = RF_MAX;
	}
	if(rf_freq < RF_MIN){
		rf_freq = RF_MIN;
	}
/*
	tfreq = rf_freq / PDF;
	tfrq_intg = (USR_INT32U)tfreq;
	tfrq_frac = (USR_INT32U)((tfreq - tfrq_intg) * _2_24);
//	ch01_reg03.chip_intg = tfrq_intg;
//	ch01_reg04.chip_frac = tfrq_frac;
	
	write_pll(lchannal, REG03H, tfrq_intg);
	write_pll(lchannal, REG04H, tfrq_frac);
*/
	tdiv_radio = rf_div_radio(rf_freq);
	tfreq = rf_freq * tdiv_radio / PDF;
	tfrq_intg = (USR_INT32U)tfreq;
	tfrq_frac = (USR_INT32U)((tfreq - tfrq_intg) * _2_24);
	
	if(tdiv_radio > 2){
		tdiv_radio = RF_OUT_BUF_GAIN | tdiv_radio;
	}
	else{
		tdiv_radio = DIV_OUT_STAG_GAIN | RF_OUT_BUF_GAIN | tdiv_radio;
	}
	write_vco(lchannal, REG02H, tdiv_radio);
	write_vco(lchannal, REG00H, 0x0);
	
	write_pll(lchannal, REG03H, tfrq_intg);
	write_pll(lchannal, REG04H, tfrq_frac);
}

static USR_INT32U rf_div_radio(USR_FP64 rf_freq)
{
	USR_INT32U radio;
	radio = (USR_INT32U)(RF_MAX / rf_freq);
	if(radio > 62){
		radio = 62;
	}
	if(radio > 2){
		radio &= 0xFFFFFFFE;
	}
	return radio;
}

void chage_gain(USR_INT08U lchannal, USR_INT08U gain)
{
	USR_INT32U vco_02;
	vco_02 = print_vco(lchannal, VCO_REG02H);
	vco_02 &= 0xFF3F;
	vco_02 |= gain << 6;
	write_vco(lchannal, VCO_REG02H, vco_02);
}
